\chapter{can\+\_\+comm }
\hypertarget{md__c_1_2_users_2_a_s_u_s_2_desktop_2dm-ctrl_h7-balance-9025test_2modules_2can__comm_2can__comm}{}\label{md__c_1_2_users_2_a_s_u_s_2_desktop_2dm-ctrl_h7-balance-9025test_2modules_2can__comm_2can__comm}\index{can\_comm@{can\_comm}}
\label{md__c_1_2_users_2_a_s_u_s_2_desktop_2dm-ctrl_h7-balance-9025test_2modules_2can__comm_2can__comm_autotoc_md40}%
\Hypertarget{md__c_1_2_users_2_a_s_u_s_2_desktop_2dm-ctrl_h7-balance-9025test_2modules_2can__comm_2can__comm_autotoc_md40}%




\href{mailto:neozng1@hnu.edu.cn}{\texttt{neozng1@hnu.\+edu.\+cn}}

\begin{quote}
TODO\+:


\begin{DoxyEnumerate}
\item 对{\ttfamily CANComm\+Get()}进行修改，使得其可以返回数据是否更新的相关信息。 
\end{DoxyEnumerate}\end{quote}
\hypertarget{md__c_1_2_users_2_a_s_u_s_2_desktop_2dm-ctrl_h7-balance-9025test_2modules_2can__comm_2can__comm_autotoc_md41}{}\doxysection{\texorpdfstring{重要提醒}{重要提醒}}\label{md__c_1_2_users_2_a_s_u_s_2_desktop_2dm-ctrl_h7-balance-9025test_2modules_2can__comm_2can__comm_autotoc_md41}
如果传输过程中出现多次丢包或长度校验不通过，尤其是传输长度较大的时候，请开启\+CAN的\+Auto Retransmission，并尝试修改\+CANComm实例的发送和接受\+ID（以提高在总线仲裁中的优先级）。\hypertarget{md__c_1_2_users_2_a_s_u_s_2_desktop_2dm-ctrl_h7-balance-9025test_2modules_2can__comm_2can__comm_autotoc_md42}{}\doxysection{\texorpdfstring{总览和封装说明}{总览和封装说明}}\label{md__c_1_2_users_2_a_s_u_s_2_desktop_2dm-ctrl_h7-balance-9025test_2modules_2can__comm_2can__comm_autotoc_md42}
CAN comm是用于\+CAN多机通信的模块。你不需要关心实现的协议，\texorpdfstring{$\ast$}{*}\texorpdfstring{$\ast$}{*}只需要传入你想发送/接收的结构体的长度\texorpdfstring{$\ast$}{*}\texorpdfstring{$\ast$}{*}（通过{\ttfamily sizeof()}获取）即可。单帧发送长度目前限制为60字节，如果需要加长可以在{\ttfamily \doxylink{can__comm_8h}{can\+\_\+comm.\+h}}中修改{\ttfamily CAN\+\_\+\+COMM\+\_\+\+MAX\+\_\+\+BUFFSIZE}的定义值。注意\+CAN的负载以及使用此模块的发送频率，否则可能造成堵塞。\hypertarget{md__c_1_2_users_2_a_s_u_s_2_desktop_2dm-ctrl_h7-balance-9025test_2modules_2can__comm_2can__comm_autotoc_md43}{}\doxysection{\texorpdfstring{代码结构}{代码结构}}\label{md__c_1_2_users_2_a_s_u_s_2_desktop_2dm-ctrl_h7-balance-9025test_2modules_2can__comm_2can__comm_autotoc_md43}
.h中放置的是数据定义和外部接口，以及协议的定义和宏，.\+c中包含一些私有函数。\hypertarget{md__c_1_2_users_2_a_s_u_s_2_desktop_2dm-ctrl_h7-balance-9025test_2modules_2can__comm_2can__comm_autotoc_md44}{}\doxysection{\texorpdfstring{外部接口}{外部接口}}\label{md__c_1_2_users_2_a_s_u_s_2_desktop_2dm-ctrl_h7-balance-9025test_2modules_2can__comm_2can__comm_autotoc_md44}

\begin{DoxyCode}{0}
\DoxyCodeLine{\mbox{\hyperlink{struct_c_a_n_comm_instance}{CANCommInstance}}\ *\mbox{\hyperlink{can__comm_8h_a611c266bef866f02414a73b7d5584f86}{CANCommInit}}(\mbox{\hyperlink{struct_c_a_n_comm___init___config__s}{CANComm\_Init\_Config\_s}}*\ comm\_config);}
\DoxyCodeLine{\textcolor{keywordtype}{void}\ \mbox{\hyperlink{can__comm_8h_a034f32d1bf2deb6386ed06690f41a7a6}{CANCommSend}}(\mbox{\hyperlink{struct_c_a_n_comm_instance}{CANCommInstance}}\ *instance,\ uint8\_t\ *data);}
\DoxyCodeLine{\textcolor{keywordtype}{void}\ *\mbox{\hyperlink{can__comm_8h_ac3cf44018acff09b65450d846df10b6d}{CANCommGet}}(\mbox{\hyperlink{struct_c_a_n_comm_instance}{CANCommInstance}}\ *instance);}
\DoxyCodeLine{uint8\_t\ \mbox{\hyperlink{can__comm_8h_a3e10f1654f1cea65cdb5f1e37912140d}{CANCommIsOnline}}(\mbox{\hyperlink{struct_c_a_n_comm_instance}{CANCommInstance}}\ *instance);}

\end{DoxyCode}


第一个函数将会初始化一个\+CANComm实例，返回其指针。使用\+CANComm进行通信的应用应该保存返回的指针。初始化需要传入一个初始化结构体。请在应用初始化的时候调用该函数。推荐的结构体配置方式如下：


\begin{DoxyCode}{0}
\DoxyCodeLine{\textcolor{comment}{/*\ 初始化结构体的定义\ */}}
\DoxyCodeLine{\textcolor{keyword}{typedef}\ \textcolor{keyword}{struct}}
\DoxyCodeLine{\{}
\DoxyCodeLine{\ \ \ \ can\_instance\_config\_s\ can\_config;}
\DoxyCodeLine{\ \ \ \ uint8\_t\ send\_data\_len;\ \textcolor{comment}{//发送数据长度}}
\DoxyCodeLine{\ \ \ \ uint8\_t\ recv\_data\_len;\ \textcolor{comment}{//接收数据长度,两者请用sizeof获取}}
\DoxyCodeLine{\}\ \mbox{\hyperlink{struct_c_a_n_comm___init___config__s}{CANComm\_Init\_Config\_s}};}
\DoxyCodeLine{}
\DoxyCodeLine{\mbox{\hyperlink{struct_c_a_n_comm___init___config__s}{CANComm\_Init\_Config\_s}}\ cconfig\ =\ \{}
\DoxyCodeLine{\ \ .can\_config\ =\ \{}
\DoxyCodeLine{\ \ \ \ \ \ \ \ \ \ \ \ .can\_handle=\&hcan1,}
\DoxyCodeLine{\ \ \ \ \ \ \ \ \ \ \ \ .tx\_id=0x02,}
\DoxyCodeLine{\ \ \ \ \ \ \ \ \ \ \ \ .rx\_id=0x03\},}
\DoxyCodeLine{\ \ .send\_data\_len\ =\ \textcolor{keyword}{sizeof}(your\_data\_structure),}
\DoxyCodeLine{\ \ .recv\_data\_len\ =\ \textcolor{keyword}{sizeof}(recv\_data\_structure)}
\DoxyCodeLine{\};}

\end{DoxyCode}


第二个函数将会通过\+CAN发送一帧数据。这里的“帧”不是\+CAN的一帧报文，而是你使用的数据。在\+CANComm初始化的时候，使用sizeof获得你要发送的数据的长度。调用此函数时，将你的数据结构或数据cast成{\ttfamily u8}类型的指针传入即可。==\texorpdfstring{$\ast$}{*}\texorpdfstring{$\ast$}{*}特别注意，你的结构体需要使用预编译指令{\ttfamily \#pragma pack(1)}以及{\ttfamily \#pragma pack()}包裹\texorpdfstring{$\ast$}{*}\texorpdfstring{$\ast$}{*}==，从而进行字节压缩而不进行字节对齐，如：


\begin{DoxyCode}{0}
\DoxyCodeLine{\textcolor{preprocessor}{\#pragma\ pack(1)}}
\DoxyCodeLine{\textcolor{keyword}{typedef}\ \textcolor{keyword}{struct}}
\DoxyCodeLine{\{}
\DoxyCodeLine{\ \ \ \ uint8\_t\ aa;}
\DoxyCodeLine{\ \ \ \ \textcolor{keywordtype}{float}\ bb;}
\DoxyCodeLine{\ \ \ \ \textcolor{keywordtype}{double}\ cc;}
\DoxyCodeLine{\ \ \ \ uint16\_t\ dd;}
\DoxyCodeLine{\}\ some\_struct;}
\DoxyCodeLine{\textcolor{preprocessor}{\#pragma\ pack()}}

\end{DoxyCode}


只有这样，这个结构体才不会进行padding扩充字节实现字节对齐。你可以尝试一下，如果不使用pack处理，上面的结构体将会占据18个字节以上的空间；开启pack后，会降低至15。更多关于字节对齐的内容，自行查询。

\begin{quote}
后期可能更新字节对齐和内存访问相关的教程。 \end{quote}


{\ttfamily CANComm\+Get()}是获取来自\+CANComm接收到的数据的接口，返回值为一个void类型指针，你需要通过\texorpdfstring{$\ast$}{*}\texorpdfstring{$\ast$}{*}强制类型转换\texorpdfstring{$\ast$}{*}\texorpdfstring{$\ast$}{*}将其变为你设定的接收类型指针，然后就可以访问其数据了。\hypertarget{md__c_1_2_users_2_a_s_u_s_2_desktop_2dm-ctrl_h7-balance-9025test_2modules_2can__comm_2can__comm_autotoc_md45}{}\doxysection{\texorpdfstring{私有函数和变量}{私有函数和变量}}\label{md__c_1_2_users_2_a_s_u_s_2_desktop_2dm-ctrl_h7-balance-9025test_2modules_2can__comm_2can__comm_autotoc_md45}

\begin{DoxyCode}{0}
\DoxyCodeLine{\textcolor{keyword}{static}\ \mbox{\hyperlink{struct_c_a_n_comm_instance}{CANCommInstance}}\ *can\_comm\_instance[MX\_CAN\_COMM\_COUNT]\ =\ \{NULL\};}
\DoxyCodeLine{\textcolor{keyword}{static}\ uint8\_t\ idx;\ }
\DoxyCodeLine{\textcolor{keyword}{static}\ \textcolor{keywordtype}{void}\ CANCommResetRx(\mbox{\hyperlink{struct_c_a_n_comm_instance}{CANCommInstance}}\ *ins);}
\DoxyCodeLine{\textcolor{keyword}{static}\ \textcolor{keywordtype}{void}\ CANCommRxCallback(can\_instance\ *\_instance);}

\end{DoxyCode}


第一个指针数组保存所有的can comm实例，从而在callback中区分不同实例。idx是初始化使用的索引，用于确定每个can comm实例指针存放的位置。

{\ttfamily CANComm\+Reset\+Rx()}在{\ttfamily CANComm\+Rx\+Callback()}中多次被调用，用于清空接收缓冲区。

{\ttfamily CANComm\+Rx\+Callback()}是\+CAN comm初始化can实例时的回调函数，用于can接收中断，进行协议解析。\hypertarget{md__c_1_2_users_2_a_s_u_s_2_desktop_2dm-ctrl_h7-balance-9025test_2modules_2can__comm_2can__comm_autotoc_md46}{}\doxysection{\texorpdfstring{使用范例}{使用范例}}\label{md__c_1_2_users_2_a_s_u_s_2_desktop_2dm-ctrl_h7-balance-9025test_2modules_2can__comm_2can__comm_autotoc_md46}
例如，这里要发送的数据是一个float，接收的数据是如下的{\ttfamily struct}，\texorpdfstring{$\ast$}{*}\texorpdfstring{$\ast$}{*}==注意要使用pack==\texorpdfstring{$\ast$}{*}\texorpdfstring{$\ast$}{*}：


\begin{DoxyCode}{0}
\DoxyCodeLine{\textcolor{preprocessor}{\#pragma\ pack(1)}}
\DoxyCodeLine{\textcolor{keyword}{struct\ }test}
\DoxyCodeLine{\{}
\DoxyCodeLine{\ \textcolor{keywordtype}{float}\ aa;}
\DoxyCodeLine{\ \textcolor{keywordtype}{float}\ bb;}
\DoxyCodeLine{\ \textcolor{keywordtype}{float}\ cc;}
\DoxyCodeLine{\ uint16\_t\ dd;}
\DoxyCodeLine{\};}
\DoxyCodeLine{\textcolor{preprocessor}{\#pragma\ pack()}}

\end{DoxyCode}


初始化时设置如下：


\begin{DoxyCode}{0}
\DoxyCodeLine{\mbox{\hyperlink{struct_c_a_n_comm___init___config__s}{CANComm\_Init\_Config\_s}}\ cconfig\ =\ \{}
\DoxyCodeLine{\ \ .can\_config\ =\ \{}
\DoxyCodeLine{\ \ \ \ \ \ \ \ \ \ \ \ .can\_handle=\&hcan1,}
\DoxyCodeLine{\ \ \ \ \ \ \ \ \ \ \ \ .tx\_id=0x02,}
\DoxyCodeLine{\ \ \ \ \ \ \ \ \ \ \ \ .rx\_id=0x03\},}
\DoxyCodeLine{\ \ .send\_data\_len\ =\ \textcolor{keyword}{sizeof}(float),}
\DoxyCodeLine{\ \ .recv\_data\_len\ =\ \textcolor{keyword}{sizeof}(\textcolor{keyword}{struct}\ test)}
\DoxyCodeLine{\};}
\DoxyCodeLine{\mbox{\hyperlink{struct_c_a_n_comm_instance}{CANCommInstance}}*\ ins\ =\ \mbox{\hyperlink{can__comm_8h_a611c266bef866f02414a73b7d5584f86}{CANCommInit}}(\&cconfig);}

\end{DoxyCode}


通过{\ttfamily CANComm\+Get()}并使用强制类型转换获得接收到的数据指针：


\begin{DoxyCode}{0}
\DoxyCodeLine{\textcolor{keyword}{struct\ }test*\ data\_ptr=(\textcolor{keyword}{struct\ }test*)\mbox{\hyperlink{can__comm_8h_ac3cf44018acff09b65450d846df10b6d}{CANCommGet}}(ins)}

\end{DoxyCode}


发送通过{\ttfamily CANComm\+Send()}，建议使用强制类型转换：


\begin{DoxyCode}{0}
\DoxyCodeLine{\textcolor{keywordtype}{float}\ tx=114.514;}
\DoxyCodeLine{\mbox{\hyperlink{can__comm_8h_a034f32d1bf2deb6386ed06690f41a7a6}{CANCommSend}}(ins,\ (uint8\_t*)\&tx);}

\end{DoxyCode}
\hypertarget{md__c_1_2_users_2_a_s_u_s_2_desktop_2dm-ctrl_h7-balance-9025test_2modules_2can__comm_2can__comm_autotoc_md47}{}\doxysection{\texorpdfstring{接收解析流程}{接收解析流程}}\label{md__c_1_2_users_2_a_s_u_s_2_desktop_2dm-ctrl_h7-balance-9025test_2modules_2can__comm_2can__comm_autotoc_md47}
CAN comm的通信协议如下：

\tabulinesep=1mm
\begin{longtabu}spread 0pt [c]{*{5}{|X[-1]}|}
\hline
\PBS\centering \cellcolor{\tableheadbgcolor}\textbf{ 帧头  }&\PBS\centering \cellcolor{\tableheadbgcolor}\textbf{ 数据长度  }&\PBS\centering \cellcolor{\tableheadbgcolor}\textbf{ 数据  }&\PBS\centering \cellcolor{\tableheadbgcolor}\textbf{ crc8校验  }&\PBS\centering \cellcolor{\tableheadbgcolor}\textbf{ 帧尾  }\\\cline{1-5}
\endfirsthead
\hline
\endfoot
\hline
\PBS\centering \cellcolor{\tableheadbgcolor}\textbf{ 帧头  }&\PBS\centering \cellcolor{\tableheadbgcolor}\textbf{ 数据长度  }&\PBS\centering \cellcolor{\tableheadbgcolor}\textbf{ 数据  }&\PBS\centering \cellcolor{\tableheadbgcolor}\textbf{ crc8校验  }&\PBS\centering \cellcolor{\tableheadbgcolor}\textbf{ 帧尾  }\\\cline{1-5}
\endhead
\textquotesingle{}s\textquotesingle{}（0x73）  &0\texorpdfstring{$\sim$}{\string~}255  &最大60（可修改）  &校验码  &\textquotesingle{}e\textquotesingle{}（0x65）  \\\cline{1-5}
1-\/byte  &1-\/byte  &n-\/byte  &1-\/byte  &1-\/byte  \\\cline{1-5}
\end{longtabu}


接收的流程见代码注释。

流程图如下： 